﻿using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Xml.Linq;

using iopt.solvency.pillarone.client.desktop.Views;
using Microsoft.VisualBasic;

namespace iopt.solvency.pillarone.client.desktop.ViewModels
{
	    [Serializable()]
	public class ModelParameterDefinition : DefinitionBase
	{
	
		public ModelParameterDefinition()
		{
		}
	
		protected internal virtual XElement GetXml()
		{
			return null;
		}
	
	
	
		private string _Format;
		public string Format {
			get { return _Format; }
			set {
				_Format = value;
				OnPropertyChanged("Format");
			}
		}
	
		private string _Legend;
		public string Legend {
			get { return string.IsNullOrEmpty(_Legend) ? _Name : _Legend; }
			set {
				_Legend = value;
				OnPropertyChanged("Legend");
			}
		}
	
	
		private ModelParamUnderLyingType _UnderlyingType = ModelParamUnderLyingType.Double;
		public ModelParamUnderLyingType UnderlyingType {
			get { return _UnderlyingType; }
			set {
				_UnderlyingType = value;
				OnPropertyChanged("UnderlyingType");
				UpdateCode();
			}
		}
	
		private bool _IsSingleton;
		public bool IsSingleton {
			get { return _IsSingleton; }
			set {
				_IsSingleton = value;
				OnPropertyChanged("IsSingleton");
				UpdateCode();
			}
		}
	
		private bool _IsSegmentable;
		public bool IsSegmentable {
			get { return _IsSegmentable; }
			set {
				_IsSegmentable = value;
				if (value) {
					IsUnique = true;
					IsTable = false;
				}
				OnPropertyChanged("IsSegmentable");
				UpdateCode();
			}
		}
	
		private bool _IsUnique;
		public bool IsUnique {
			get { return _IsUnique; }
			set {
				_IsUnique = value;
				OnPropertyChanged("IsUnique");
				UpdateCode();
			}
		}
	
		private bool _IsVector;
		public bool IsVector {
			get { return _IsVector; }
			set {
				_IsVector = value;
				OnPropertyChanged("IsVector");
				UpdateCode();
			}
		}
	
		private bool _IsMatrix;
		public bool IsMatrix {
			get { return _IsMatrix; }
			set {
				_IsMatrix = value;
				OnPropertyChanged("IsMatrix");
				UpdateCode();
			}
		}
	
		private bool _IsTable;
		public bool IsTable {
			get { return _IsTable; }
			set {
				_IsTable = value;
				OnPropertyChanged("IsTable");
				UpdateCode();
			}
		}
	
		private bool _IsFixed;
		public bool IsFixed {
			get { return _IsFixed; }
			set {
				_IsFixed = value;
				OnPropertyChanged("IsFixed");
				UpdateCode();
			}
		}
	
		private bool _IsCalculable;
		public bool IsCalculable {
			get { return _IsCalculable; }
			set {
				_IsCalculable = value;
				OnPropertyChanged("IsCalculable");
				UpdateCode();
			}
		}
	
		private bool _IsSheet;
		public bool IsSheet {
			get { return _IsSheet; }
			set {
				_IsSheet = value;
				OnPropertyChanged("IsSheet");
				UpdateCode();
			}
		}
	
		private string _Name;
		public string Name {
			get { return _Name; }
			set {
				_Name = value;
				OnPropertyChanged("Name");
				UpdateCode();
			}
		}
	
		private string _Constraint;
		public string Constraint {
			get { return _Constraint; }
			set {
				_Constraint = value;
				OnPropertyChanged("Constraint");
				UpdateCode();
			}
		}
	
		private string _Code;
		public string Code {
			get { return _Code; }
			set {
				_Code = value;
				OnPropertyChanged("Code");
			}
		}
	
		private bool _AutoGenerateCode = false;
		public bool AutoGenerateCode {
			get { return _AutoGenerateCode; }
			set {
				_AutoGenerateCode = value;
				OnPropertyChanged("AutoGenerateCode");
			}
		}
	
		private void UpdateCode()
		{
			if (AutoGenerateCode) {
				Code = GetCode(new VBCodeProvider());
			}
		}
	
		public string GetCode(CodeDomProvider provider)
		{
			CodeNamespace ns = new CodeNamespace("OMANE.Modules.Builder.Generated.Parameters");
	
			CodeTypeDeclaration t = new CodeTypeDeclaration(Name + "_Class");
			dynamic utype = GetTypeFromUnderLyingType(this.UnderlyingType);
			//      Dim basetype = GetType(ModelParameter(Of )).MakeGenericType(utype)
			//     t.BaseTypes.Add(basetype)
	
			if (IsSegmentable) {
				dynamic addvarsmethod = new CodeMemberMethod();
				addvarsmethod.Name = "AddVars";
				addvarsmethod.Attributes = MemberAttributes.Public;
				dynamic varparam = new CodeParameterDeclarationExpression(typeof(string[]), "variables");
				varparam.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(ParamArrayAttribute))));
				addvarsmethod.Parameters.Add(varparam);
				addvarsmethod.ReturnType = null;
	
				dynamic removevarsmethod = new CodeMemberMethod();
				removevarsmethod.Name = "RemoveVars";
				removevarsmethod.Attributes = MemberAttributes.Public;
				varparam = new CodeParameterDeclarationExpression(typeof(string[]), "variables");
				varparam.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(ParamArrayAttribute))));
				removevarsmethod.Parameters.Add(varparam);
				removevarsmethod.ReturnType = null;
	
				dynamic varsdata = new CodeMemberProperty();
				varsdata.Name = "Data";
				varsdata.Attributes = MemberAttributes.Public;
				varsdata.HasGet = true;
				varsdata.HasSet = false;
	
				varsdata.Type = new CodeTypeReference(typeof(System.Data.DataView));
	
	
				t.Members.Add(addvarsmethod);
				t.Members.Add(removevarsmethod);
				t.Members.Add(varsdata);
			}
	
			if (IsUnique) {
				dynamic varsdata = new CodeMemberProperty();
				varsdata.Name = "Value";
				varsdata.Attributes = MemberAttributes.Public;
				varsdata.HasGet = true;
				varsdata.HasSet = true;
	
				varsdata.Type = utype;
	
				t.Members.Add(varsdata);
			}
	
	
			if (IsVector) {
				dynamic varsdata = new CodeMemberProperty();
				varsdata.Name = "Value";
				varsdata.Attributes = MemberAttributes.Public;
				varsdata.HasGet = true;
				varsdata.HasSet = true;
				varsdata.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "index"));
				varsdata.Type = utype;
	
				dynamic vars2data = new CodeMemberProperty();
				vars2data.Name = "Value";
				vars2data.Attributes = MemberAttributes.Public;
				vars2data.HasGet = true;
				vars2data.HasSet = true;
				vars2data.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "startindex"));
				vars2data.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "endindex"));
	
				vars2data.Type = new CodeTypeReference(typeof(object));
				//(GetType(Vector(Of )), .MakeGenericType(utype))
	
				t.Members.Add(varsdata);
				t.Members.Add(vars2data);
			}
	
			if (IsCalculable) {
				dynamic computemethod = new CodeMemberMethod();
				computemethod.Name = "Compute";
				computemethod.Attributes = MemberAttributes.Public;
				computemethod.ReturnType = null;
	
				t.Members.Add(computemethod);
			}
	
			if (UnderlyingType == ModelParamUnderLyingType.Case) {
	
				if (!string.IsNullOrEmpty(Constraint)) {
					if (Constraint.Trim().StartsWith("=")) {
						dynamic computemethod = new CodeMemberMethod();
						computemethod.Name = "ExtractValues";
						computemethod.Attributes = MemberAttributes.Family;
						computemethod.ReturnType = null;
						t.Members.Add(computemethod);
					} else {
						dynamic values = Constraint.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
	
						dynamic valuenums = new CodeTypeDeclaration("Cases");
						valuenums.IsEnum = true;
						valuenums.Attributes = MemberAttributes.Public;
	
						foreach (var elt in values) {
							if (!string.IsNullOrEmpty(elt.Trim())) {
								valuenums.Members.Add(new CodeMemberField(typeof(int), elt.Trim()));
							}
						}
	
						t.Members.Add(valuenums);
	
					}
				}
			}
			ns.Types.Add(t);
	
			var strwriter = new System.IO.StringWriter();
			var options = new CodeGeneratorOptions();
			options.BlankLinesBetweenMembers = true;
			provider.GenerateCodeFromNamespace(ns, strwriter, options);
			dynamic result = strwriter.ToString();
			strwriter.Dispose();
			return result;
		}
	
		private CodeTypeReference GetTypeFromUnderLyingType(ModelParamUnderLyingType utype)
		{
			switch (utype) {
				case ModelParamUnderLyingType.Boolean:
					return new CodeTypeReference(typeof(bool));
				case ModelParamUnderLyingType.Case:
					dynamic result = new CodeTypeReference(Name + "." + "Cases");
					return result;
				case ModelParamUnderLyingType.Date:
					return new CodeTypeReference(typeof(DateTime));
				case ModelParamUnderLyingType.Double:
					return new CodeTypeReference(typeof(double));
				case ModelParamUnderLyingType.Mixed:
					return new CodeTypeReference(typeof(object));
				case ModelParamUnderLyingType.Time:
					return new CodeTypeReference(typeof(TimeSpan));
				case ModelParamUnderLyingType.Uncertain:
//	new CodeTypeReference(typeof(UncertainValue))
					return null;
			}
	
			return new CodeTypeReference(typeof(object));
		}
	}
}
